home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / D-G / DropInfo ƒ / DI⁄C / DIStuff.c next >
Encoding:
C/C++ Source or Header  |  1992-04-21  |  15.1 KB  |  639 lines  |  [TEXT/KAHL]

  1. /******************************************************************************
  2. **
  3. **  Project Name:    DropInfo
  4. **     File Name:    DIStuff.c
  5. **
  6. **   Description:    Contains the DropInfo-specific code
  7. **
  8. *******************************************************************************
  9. **                       A U T H O R   I D E N T I T Y
  10. *******************************************************************************
  11. **
  12. **    Initials    Name
  13. **    --------    -----------------------------------------------
  14. **    SCS            Stephan Somogyi
  15. **    LDR            Leonard Rosenthol
  16. **
  17. *******************************************************************************
  18. **                      R E V I S I O N   H I S T O R Y
  19. *******************************************************************************
  20. **
  21. **      Date        Vers    Author    Description
  22. **    --------    -----    ------    ---------------------------------------------
  23. **    22.12.91            LDR        Changed an ExitToShell into a SendQuitToSelf
  24. **
  25. **    06.09.91    a(-1)    SCS        files implemented except for resmap locking
  26. **    10.09.91    a2                removed resmap locking as there is no nice way to do it
  27. **                                added folders, not sure they work the way they should, though…
  28. **    25.09.91    a3                added the laurie gill feature: cmd-q quits regardless of whether
  29. **                                there are any files/folders left to deal with. added flushvols.
  30. **    26.09.91    a4                added change all. fixed some stupid a3 bugs.
  31. **    27.09.91    b1                added dimming of change all if only one file dropped. source
  32. **                                reality check.
  33. **    01.10.91    b1                changed oapp behavior to what it should be. better volume supt.
  34. **    09.10.91    fc1                moved initial selection to type rather than creator
  35. **                fc2                minor divergence where SCS and LDR both did similar things
  36. **    29.11.91    fc3                used 11/24/91 DropShell
  37. **                                made non-inline MyBitTst and MyBitSetClr
  38. **                                made DI compilable by both THINK and MPW
  39. **    30.11.91    fc3+    LDR        made MUCH more use of enum's & #defines rather than hard coded values
  40. **                                Also added some comments
  41. **                                Applied hack in ItsADir for MPW C compiler
  42. **    01.12.91    F4        SCS        Reformatting and commenting
  43. **                                Replaced IUEqualString with EqualString for better case sensitivity
  44. **
  45. ******************************************************************************/
  46.  
  47. #ifndef THINK_C
  48.     #define TRUE true
  49.     #define FALSE false
  50.  
  51.     #include <Dialogs.h>
  52.     #include <Files.h>
  53.     #include <Memory.h>
  54. #endif
  55.  
  56.  
  57. #include "DIUtils.h"
  58.  
  59. #include "DIStuff.h"
  60.  
  61.  
  62. /*    bit numbers for the relevant flags in the FInfo struct */
  63. enum    {
  64.     bIsLocked = 0,
  65.     bIsDir = 4,
  66.     bIsShared = 6,
  67.     bHasNoINITs,
  68.     bInited,
  69.     bCustomIcn = 10,
  70.     bStationary,
  71.     bNameLock,
  72.     bBundle,
  73.     bInvisible,
  74.     bIsAlias
  75. };
  76.  
  77. /*    contains the various bits' states
  78.         [0] dirty flag, if anything is changed and needs to be saved this is TRUE
  79.         [1] file locked state
  80. */
  81. static Boolean            fileBits[bIsAlias];
  82.  
  83. /*    tells us whether to quit and ignore any other FSSpecs */
  84. static Boolean            gAbort;
  85.  
  86. /*    tells us if change all is in effect, if it's files or folders, and whether the user
  87.     has already been warned about mixing the two */
  88. Boolean                    gChgAll = 0, gIsFiles, gWarned = 0;
  89.  
  90. /*    these are globals since in ChgAll mode we're doing bunches of files/folders */
  91. static Str255            gTypeStr, gCreaStr;
  92.  
  93. /*    this is a global because it is reused when we're processing a volume */
  94. static Str255            gTempStr;
  95.  
  96. /*    is there only one file/folder in the list */
  97. Boolean                    gOnlyOne = 0;
  98.  
  99.  
  100. /*    Does a bit test in 68k order, not the reverse like the Toolbox's BitTst() */
  101. Boolean
  102. MyBitTst(unsigned short pBMap, unsigned short pBitNum)
  103. {
  104. #ifdef THINK_C
  105.     asm    {
  106.         moveq    #0,d0
  107.         moveq    #0,d1
  108.         move.w    pBMap,d0
  109.         move.w    pBitNum,d1
  110.         btst    d1,d0
  111.         beq.s    @1
  112.         moveq    #1,d0
  113.         bra.s    @2
  114. @1:        moveq    #0,d0
  115. @2:
  116.     }
  117. #else
  118.  
  119.     short        lAndMap;
  120.  
  121.     lAndMap = 1 << pBitNum;
  122.  
  123.     if (pBMap & lAndMap)
  124.         return TRUE;
  125.     else
  126.         return FALSE;
  127.  
  128. #endif
  129. }
  130.  
  131.  
  132. /*    Clears or sets the specified bit depending on pState */
  133. void
  134. MyBitSetClr(unsigned short *pBMap, unsigned short pBitNum, Boolean pState)
  135. {
  136. #ifdef THINK_C
  137.     asm    {
  138.         move.l    pBMap,a0
  139.         moveq    #0,d1
  140.         move.w    pBitNum, d1
  141.  
  142.         tst.b    pState
  143.         beq.s    @1
  144.  
  145.         cmp.w    #7,d1
  146.         bgt.s    @2
  147.         bset    d1,1(a0)
  148.         bra.s    @4
  149.  
  150. @2:        subq.w    #8,d1
  151.         bset    d1,(a0)
  152.         bra.s    @4
  153.  
  154. @1:        cmp.w    #7,d1
  155.         bgt.s    @3
  156.         bclr    d1,1(a0)
  157.         bra.s    @4
  158.  
  159. @3:        subq.w    #8,d1
  160.         bclr    d1,(a0)
  161. @4:
  162.     }
  163. #else
  164.  
  165.     short    lOrMap;
  166.  
  167.     lOrMap = 1 << pBitNum;
  168.  
  169.     if (pState)
  170.         (*pBMap) |= lOrMap;
  171.     else    {
  172.         if (*pBMap & lOrMap)
  173.             (*pBMap) ^= lOrMap;
  174.     }
  175.  
  176. #endif
  177. }
  178.  
  179.  
  180. /*    toggles a Boolean and sets the dirty flag as well */
  181. void
  182. ToggleBit(Boolean *pBool)
  183. {
  184.     if (*pBool)
  185.         (*pBool) = FALSE;
  186.     else
  187.         (*pBool) = TRUE;
  188.  
  189.     fileBits[0] = TRUE;                                            // set dirty flag
  190. }
  191.  
  192.  
  193. /*    Takes a file's or folder's information and puts it in the right places in
  194.     DI's array
  195. */
  196. void
  197. InfoIn(unsigned short pFSflags, CInfoPBPtr pCBlk)
  198. {
  199.  
  200.     short            lCtr;
  201.  
  202.     if (!MyBitTst(pCBlk->hFileInfo.ioFlAttrib, bIsDir))    {        // if not dir
  203.         for (lCtr = bIsShared; lCtr <= bIsAlias; lCtr++)    {
  204.             if (MyBitTst(pFSflags, lCtr))
  205.                 fileBits[lCtr] = TRUE;
  206.             else
  207.                 fileBits[lCtr] = FALSE;
  208.         }
  209.  
  210.         if (MyBitTst(pCBlk->hFileInfo.ioFlAttrib,bIsLocked))
  211.             fileBits[1] = TRUE;                                    // file lock state
  212.         else
  213.             fileBits[1] = FALSE;
  214.  
  215.         fileBits[0] = FALSE;                                    // dirty flag clear
  216.     }
  217.     else    {                                                    // it's a dir
  218.         if (MyBitTst(pCBlk->hFileInfo.ioFlFndrInfo.fdFlags,bInvisible))    // invisible
  219.             fileBits[7] = TRUE;
  220.         else
  221.             fileBits[7] = FALSE;
  222.  
  223.         if (MyBitTst(pCBlk->hFileInfo.ioFlFndrInfo.fdFlags,bNameLock))    // locked name
  224.             fileBits[6] = TRUE;
  225.         else
  226.             fileBits[6] = FALSE;
  227.  
  228.         if (MyBitTst(pCBlk->hFileInfo.ioFlFndrInfo.fdFlags,bCustomIcn))    // custom
  229.             fileBits[5] = TRUE;
  230.         else
  231.             fileBits[5] = FALSE;
  232.  
  233.         if (MyBitTst(pCBlk->hFileInfo.ioFlFndrInfo.fdFlags,bInited))    // inited
  234.             fileBits[4] = TRUE;
  235.         else
  236.             fileBits[4] = FALSE;
  237.  
  238.         fileBits[0] = FALSE;                                    // dirty flag clear
  239.     }
  240. }
  241.  
  242.  
  243. /*    The reverse of InfoIn; takes the file's or folder's information from DI's array
  244.     and fills out the OS' data structure
  245. */
  246. void
  247. InfoOut(unsigned short *pFSflags, FSSpecPtr pFSS, CInfoPBPtr pCBlk)
  248. {
  249.     OSErr            lErr;
  250.     short            lCtr;
  251.  
  252.     if (!MyBitTst(pCBlk->hFileInfo.ioFlAttrib,bIsDir))    {            // if not dir
  253.  
  254.         for (lCtr = bIsShared; lCtr <= bIsAlias; lCtr++)
  255.             MyBitSetClr(pFSflags, lCtr, fileBits[lCtr]);
  256.     
  257.             if (fileBits[1])                                    // file lock
  258.                 lErr = FSpSetFLock(pFSS);
  259.             else
  260.                 lErr = FSpRstFLock(pFSS);
  261.     }
  262.     else    {                                                    // it's a dir
  263.         MyBitSetClr(pFSflags, bInvisible, fileBits[7]);
  264.         MyBitSetClr(pFSflags, bNameLock, fileBits[6]);
  265.         MyBitSetClr(pFSflags, bCustomIcn, fileBits[5]);
  266.         MyBitSetClr(pFSflags, bInited, fileBits[4]);
  267.     }
  268. }
  269.  
  270.  
  271. /*    ModalDialog filterProc 
  272.     In addition to the standard key support, it also supports Cmd-Q as cancel
  273. */
  274. pascal Boolean
  275. MyStdKeyFilter(DialogPtr pDial, EventRecord *pEventRec, short *pItemHit)
  276. {
  277.     unsigned char        lKey;
  278.  
  279.     if ((pEventRec->what == keyDown) || (pEventRec->what == autoKey))    {
  280.         lKey = pEventRec->message & 0xFF;
  281.         switch (lKey)    {
  282.             case 13: case 3:    {    // if return or enter keys
  283.                 *pItemHit = 1;
  284.                 FlashItem(pDial, 1);
  285.                 return TRUE;
  286.             }
  287.             case 27: case '.': case '>':    {    // if esc or  cmd-.
  288.                 if ((pEventRec->modifiers & cmdKey) || (lKey == 27))    {
  289.                     *pItemHit = 2;
  290.                     FlashItem(pDial, 2);
  291.                     return TRUE;
  292.                 }
  293.             }
  294.             case 'q': case 'Q':    {
  295.                 if (pEventRec->modifiers & cmdKey)    {
  296.                     *pItemHit = 2;
  297.                     FlashItem(pDial, 2);
  298.                     gAbort = TRUE;
  299.                     return TRUE;
  300.                 }
  301.             }
  302.             default:
  303.                 return FALSE;
  304.         }
  305.     }
  306.     else
  307.         return FALSE;
  308. }
  309.  
  310.  
  311. /*    Routine called if the thing in question is a file. This actually does the work */
  312. void
  313. ItsAFile(FSSpecPtr pFSS, CInfoPBRec *pCBlk)
  314. {
  315.     OSErr            lErr;
  316.  
  317.     FInfo            lFinfo;
  318.  
  319.     Str255            lNameStr;
  320.  
  321.     DialogPtr        lDial;
  322.  
  323.     short            lCtr;
  324.     short            lItemHit;
  325.  
  326.  
  327.     lErr = FSpGetFInfo(pFSS, &lFinfo);
  328.  
  329.     if (!gChgAll)    {
  330.         InfoIn(lFinfo.fdFlags, pCBlk);
  331.  
  332.         lDial = GetNewDialog(130, nil, (WindowPtr) -1);
  333.         DefBut(lDial);
  334.     
  335.     /*    set up the dialog    */
  336.     //    Probably should consider NOT using BlockMove
  337.     //    as it is VERY inefficient on an '040 due to CacheFlush
  338.         BlockMove(&pFSS->name, &lNameStr, pFSS->name[0]+1);
  339.         gTypeStr[0] = 4;
  340.         BlockMove(&lFinfo.fdType, &gTypeStr[1], 4);
  341.         gCreaStr[0] = 4;
  342.         BlockMove(&lFinfo.fdCreator, &gCreaStr[1], 4);
  343.         SetTxtItem(lDial, 5, (Str255 *) &lNameStr);
  344.         SetTxtItem(lDial, 3, (Str255 *) &gTypeStr);
  345.         SetTxtItem(lDial, 4, (Str255 *) &gCreaStr);
  346.         
  347.     
  348.         for (lCtr = bIsShared; lCtr <= bInited; lCtr++)
  349.             CheckBox(lDial, lCtr, fileBits[lCtr]);
  350.         for (lCtr = bCustomIcn; lCtr <= bIsAlias; lCtr++)
  351.             CheckBox(lDial, lCtr, fileBits[lCtr]);
  352.     
  353.         CheckBox(lDial, 16, fileBits[1]);                            // locked
  354.  
  355.         if (gOnlyOne)
  356.             DisEnAble(lDial, 18, FALSE);
  357.     
  358.         DrawDialog(lDial);
  359.         SelIText(lDial, 3, 0, 32767);
  360.     
  361.         do    {
  362.             gAbort = FALSE;
  363.             ModalDialog(MyStdKeyFilter, &lItemHit);
  364.             switch    (lItemHit)    {
  365.                 case 1:    {                                            // OK
  366.                     break;
  367.                 }
  368.                 case 2:    {                                            // cancel
  369.                     fileBits[0] = FALSE;                            // clear dirty flag
  370.                     break;
  371.                 }
  372.                 case 16:    {                                        // locked state
  373.                     ToggleBit(&fileBits[1]);
  374.                     CheckBox(lDial, 16, fileBits[1]);
  375.                     break;
  376.                 }
  377.                 case 18:    {                                        // change all
  378.                     gChgAll = TRUE;
  379.                     gIsFiles = TRUE;
  380.                     break;
  381.                 }
  382.                 default:    {                                        // the other bits
  383.                     ToggleBit(&fileBits[lItemHit]);
  384.                     CheckBox(lDial, lItemHit, fileBits[lItemHit]);
  385.                     break;
  386.                 }
  387.             }
  388.         }    while ((lItemHit != 1) && (lItemHit != 2) && (lItemHit != 18));
  389.     
  390.         HideWindow(lDial);
  391.         
  392.         if ((lItemHit != 2) && (!gAbort))    {                                        // if not cancel
  393.             GetTxtItem(lDial, 3, (Str255 *) &gTempStr);
  394.     
  395.             if (!EqualString(gTempStr, gTypeStr, TRUE, TRUE))    {
  396.                 //    Probably should consider NOT using BlockMove
  397.                 //    as it is VERY inefficient on an '040 due to CacheFlush
  398.                 BlockMove(&gTempStr[1], &lFinfo.fdType, 4);
  399.                 BlockMove(&gTempStr[1], &gTypeStr[1], 4);
  400.                 fileBits[0] = TRUE;
  401.             }
  402.             GetTxtItem(lDial, 4, (Str255 *) &gTempStr);
  403.             if (!EqualString(gTempStr, gCreaStr, TRUE, TRUE))    {
  404.                 //    Probably should consider NOT using BlockMove
  405.                 //    as it is VERY inefficient on an '040 due to CacheFlush
  406.                 BlockMove(&gTempStr[1], &lFinfo.fdCreator, 4);
  407.                 BlockMove(&gTempStr[1], &gCreaStr[1], 4);
  408.                 fileBits[0] = TRUE;
  409.             }
  410.             GetTxtItem(lDial, 5, (Str255 *) &gTempStr);
  411.             if (!EqualString(gTempStr, lNameStr, TRUE, TRUE))    {
  412.                 if (gTempStr[0] > 32)
  413.                     gTempStr[0] = 32;
  414.                 lErr = FSpRstFLock(pFSS);                        // will be reset later if necessary
  415.                 lErr = FSpRename(pFSS, gTempStr);
  416.     
  417.                 if (lErr == -48)    {
  418.                     lErr = Alert(132, nil);
  419.                     fileBits[0] = FALSE;
  420.                 }
  421.                 else    {
  422.                     BlockMove(&gTempStr, &pFSS->name, gTempStr[0]+1);
  423.                     fileBits[0] = TRUE;
  424.                 }
  425.             }
  426.         }
  427.         DisposDialog(lDial);
  428.     }
  429.     else    {
  430.         fileBits[0] = TRUE;
  431.         //    Probably should consider NOT using BlockMove
  432.         //    as it is VERY inefficient on an '040 due to CacheFlush
  433.         BlockMove(&gTypeStr[1], &lFinfo.fdType, 4);
  434.         BlockMove(&gCreaStr[1], &lFinfo.fdCreator, 4);
  435.     }
  436.  
  437.     if (fileBits[0])    {                                            // dirty flag is set
  438.         InfoOut(&lFinfo.fdFlags, pFSS, pCBlk);
  439.  
  440.         pCBlk->hFileInfo.ioDirID = pFSS->parID;
  441.         if (gChgAll)
  442.             pCBlk->hFileInfo.ioNamePtr = 0L;
  443.         else
  444.             pCBlk->hFileInfo.ioNamePtr = (StringPtr) &gTempStr;
  445.         lErr = PBSetCatInfo(pCBlk, FALSE);
  446.  
  447.         lErr = FSpSetFInfo(pFSS, &lFinfo);
  448.     }
  449.  
  450.     if (gAbort)    
  451.         SendQuitToSelf();                        // send ourselves a quit!
  452. }
  453.  
  454.  
  455. /*    Routine called if the thing in question is a folder. This actually does the work */
  456. void
  457. ItsADir(FSSpecPtr pFSS, CInfoPBRec *pCBlk)
  458. {
  459.     OSErr            lErr;
  460.  
  461.     FInfo            lFinfo;
  462.     HParamBlockRec    lHBlk;
  463.  
  464.     Str255            lNameStr;
  465.  
  466.     DialogPtr        lDial;
  467.  
  468.     short            lCtr;
  469.     short            lItemHit;
  470.  
  471.  
  472.     /* 
  473.         HACK ALERT!!!!!!
  474.         
  475.         In order to keep the MPW C compiler from complaining about a variable
  476.         use before initialization, we make the following bogus call. Fortunately, 
  477.         contrary to IM VI, this call doesn't work for directories and the InfoIn
  478.         routine does NOT look at that param for directories.
  479.     */
  480.     
  481.     lErr = FSpGetFInfo(pFSS, &lFinfo);
  482.     lErr = noErr;
  483.     
  484.     if (!gChgAll)    {
  485.         InfoIn(lFinfo.fdFlags, pCBlk);
  486.  
  487.         lDial = GetNewDialog(129, nil, (WindowPtr) -1);
  488.         DefBut(lDial);
  489.     
  490.     /*    set up the dialog    */
  491.     
  492.         BlockMove(&pFSS->name, &lNameStr, pFSS->name[0]+1);
  493.         SetTxtItem(lDial, 3, (Str255 *) &lNameStr);
  494.     
  495.         for (lCtr = 4; lCtr <= 7; lCtr++)
  496.             CheckBox(lDial, lCtr, fileBits[lCtr]);
  497.  
  498.         if (gOnlyOne)
  499.             DisEnAble(lDial, 8, FALSE);
  500.  
  501.         DrawDialog(lDial);
  502.         SelIText(lDial, 3, 0, 32767);
  503.     
  504.         do    {
  505.             ModalDialog(MyStdKeyFilter, &lItemHit);
  506.             switch    (lItemHit)    {
  507.                 case 1:    {                                            // OK
  508.                     break;
  509.                 }
  510.                 case 2:    {                                            // cancel
  511.                     fileBits[0] = FALSE;                            // clear dirty flag
  512.                     break;
  513.                 }
  514.                 case 8:    {                                            // change all
  515.                     gChgAll = TRUE;
  516.                     gIsFiles = FALSE;
  517.                     break;
  518.                 }
  519.                 default:    {                                        // the other bits
  520.                     ToggleBit(&fileBits[lItemHit]);
  521.                     CheckBox(lDial, lItemHit, fileBits[lItemHit]);
  522.                     break;
  523.                 }
  524.             }
  525.         }    while ((lItemHit != 1) && (lItemHit != 2) && (lItemHit != 8));
  526.     
  527.         HideWindow(lDial);
  528.     
  529.         if (gAbort)    {                                                // cmd q
  530.             DisposDialog(lDial);
  531.             ExitToShell();
  532.         }
  533.     
  534.         if (lItemHit != 2)    {                                        // if not cancel
  535.             GetTxtItem(lDial, 3, (Str255 *) &gTempStr);
  536.     
  537.             if (!EqualString(gTempStr, lNameStr, TRUE, TRUE))    {
  538.                 if (gTempStr[0] > 32)
  539.                     gTempStr[0] = 32;
  540.     
  541.                 lHBlk.ioParam.ioNamePtr = (StringPtr) &lNameStr;
  542.                 lHBlk.ioParam.ioVRefNum = pFSS->vRefNum;
  543.                 lHBlk.ioParam.ioMisc = (Ptr) &gTempStr;
  544.                 lHBlk.fileParam.ioDirID = pFSS->parID;
  545.                 lErr = PBHRename(&lHBlk, FALSE);                    // rename the dir
  546.     
  547.                 if (lErr == -48)    {
  548.                     lErr = Alert(132, nil);
  549.                     fileBits[0] = FALSE;
  550.                 }
  551.                 else
  552.                     fileBits[0] = TRUE;
  553.     
  554.             }
  555.         }
  556.         DisposDialog(lDial);
  557.     }
  558.     else
  559.         fileBits[0] = true;
  560.  
  561.     if (fileBits[0])    {                                            // dirty flag is set
  562.         InfoOut(&pCBlk->hFileInfo.ioFlFndrInfo.fdFlags, pFSS, pCBlk);
  563.  
  564.         pCBlk->hFileInfo.ioDirID = pFSS->parID;
  565.         if (!gChgAll)
  566.             pCBlk->hFileInfo.ioNamePtr = (StringPtr) &gTempStr;
  567.         lErr = PBSetCatInfo(pCBlk, FALSE);
  568.     }
  569. }
  570.  
  571.  
  572. /*    This is called by DropShell, once for every FSSpec received via odoc. GetTheInfo
  573.     is simply a dispatcher to ItsAFile and ItsAFolder. Once the alterations have been made
  574.     it also touched the parent dir's modification date, thereby causing the Finder to update
  575.     that directory's window.
  576. */
  577. void
  578. GetTheInfo(FSSpecPtr pFSS)
  579. {
  580.     OSErr            lErr;
  581.  
  582.     CInfoPBRec        lCBlk;
  583.  
  584.  
  585.     lCBlk.hFileInfo.ioVRefNum = pFSS->vRefNum;
  586.     lCBlk.hFileInfo.ioNamePtr = (StringPtr) &pFSS->name;
  587.     lCBlk.hFileInfo.ioDirID = pFSS->parID;
  588.     lCBlk.hFileInfo.ioFDirIndex = 0;
  589.     lCBlk.hFileInfo.ioCompletion = 0;
  590.  
  591.     lErr = PBGetCatInfo(&lCBlk, FALSE);
  592.  
  593.     if (!MyBitTst(lCBlk.hFileInfo.ioFlAttrib,bIsDir))    {
  594.         if (gChgAll && (!gIsFiles))    {
  595.             if (!gWarned)    {
  596.                 ParamText("\pfolders", 0,0,0);
  597.                 lErr = Alert(133, nil);
  598.                 gWarned = TRUE;
  599.             }
  600.             return;
  601.         }
  602.         else
  603.             ItsAFile(pFSS, &lCBlk);
  604.     }
  605.     else    {
  606.         if (gChgAll && gIsFiles)    {
  607.             if (!gWarned)    {
  608.                 ParamText("\pfiles", 0,0,0);
  609.                 lErr = Alert(133, nil);
  610.                 gWarned = TRUE;
  611.             }
  612.             return;
  613.         }
  614.         else
  615.             ItsADir(pFSS, &lCBlk);
  616.     }
  617.  
  618.     /*    
  619.         touch the parent dir's mod date    
  620.         We need to do this to get the Finder to update itself on demand!
  621.     */
  622.  
  623.     if (fileBits[0])    {
  624.         if (pFSS->parID != 1)                            // if it's a vol then reuse the NameStr
  625.             lCBlk.dirInfo.ioNamePtr = 0L;
  626.         lCBlk.dirInfo.ioVRefNum = pFSS->vRefNum;        
  627.         lCBlk.dirInfo.ioDrDirID = pFSS->parID;
  628.         lCBlk.dirInfo.ioFDirIndex = 0;
  629.         lCBlk.dirInfo.ioCompletion = 0;
  630.     
  631.         lErr = PBGetCatInfo(&lCBlk, FALSE);
  632.         GetDateTime(&lCBlk.dirInfo.ioDrMdDat);
  633.         lCBlk.dirInfo.ioDrDirID = pFSS->parID;
  634.         lErr = PBSetCatInfo(&lCBlk, FALSE);
  635.     
  636.         lErr = FlushVol(nil, pFSS->vRefNum);
  637.     }
  638. }
  639.